﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;

namespace WooCoo
{
    /// <summary>
    /// 应用程序上下文
    /// </summary>
    public static class ApplicationContext
    {
        #region Context Manager

        private static IContextManager _contextManager;
        
        static ApplicationContext()
        {
            var cmType = System.Configuration.ConfigurationManager.AppSettings["ContextManager"];
            if (!string.IsNullOrEmpty(cmType))
            {
                _contextManager = System.Activator.CreateInstance(Type.GetType(cmType)) as IContextManager;
            }
            else
            {
                _contextManager = new ApplicationContextManager();
            }
        }

        /// <summary>
        /// 读取和设置维护着用户及上下文信息.
        /// 根据运行环境来确定使用哪种上下文管理器        
        /// </summary>
        public static IContextManager ContextManager
        {
            get
            {
                if (!_contextManager.IsValid)
                {
                    _contextManager = new ApplicationContextManager();
                }
                return _contextManager;
            }
            set { _contextManager = value; }
        }

        #endregion

        #region User

        /// <summary>
        /// 获取或设置当前的 <see cref="IPrincipal" />
        /// 对象。
        /// </summary>
        /// <remarks>
        /// </remarks>
        public static IPrincipal User
        {
            get 
            {
                if(BeforeGetUser!=null)
                {
                    BeforeGetUser(null, EventArgs.Empty);
                }
                return ContextManager.GetUser(); 
            }
            set { ContextManager.SetUser(value); }
        }

        public static event EventHandler BeforeGetUser;

        #endregion

        #region LocalContext
        /// <summary>
        /// 返回应用程序指定的上下文数据，该数据是在当前程序域中
        /// </summary>
        /// <remarks>
        /// </remarks>
        public static HybridDictionary LocalContext
        {
            get
            {
                HybridDictionary ctx = ContextManager.GetLocalContext();
                if (ctx == null)
                {
                    ctx = new HybridDictionary();
                    ContextManager.SetLocalContext(ctx);
                }
                return ctx;
            }
        }

        #endregion

        #region Config Settings

        private static string _authenticationType;

        /// <summary>
        /// 验证方式
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks>
        /// 该值从应用程序配置文件配置点"WcdfAuthentication"读取.
        /// 如果值为"Windows"表示应用Windows集成验证.任务值为应用自
        /// 定义的验证方式.        
        /// </remarks>
        public static string AuthenticationType
        {
            get
            {
                if (_authenticationType == null)
                {
                    _authenticationType = ConfigurationManager.AppSettings["Authentication"];
                    _authenticationType = _authenticationType ?? "WooCoo";
                }
                return _authenticationType;
            }
        }

        private static string _validateUserNameType;
        /// <summary>
        /// 验证用户，描述如何对用户请求的验证方式
        /// 当为FirstLogin时，在第一次用户登陆验证后，以后的每次请求不再验证。
        /// 当为PerCall时，每次请求都进行验证。
        /// </summary>
        public static string ValidateUserNameType
        {
            get
            {
                if (_validateUserNameType == null)
                {
                    _validateUserNameType = ConfigurationManager.AppSettings["ValidateUserNameType"];
                    _validateUserNameType = _validateUserNameType ?? "FirstLogin";
                }
                return _validateUserNameType;
            }
        }

        private static string _portalProxy;

        /// <summary>
        /// 门户代理类的完全限定类型名.
        /// </summary>
        /// <value>指定的处理类或者默认"LocalProxy"处理</value>
        /// <returns></returns>
        /// <remarks>
        /// <para>
        /// 如果该值为空,将会从应用程序配置文件中读取"WcdfDataPortalProxy".        
        /// </para><para>
        /// 代理类必须继承自Wcdf.Server.IDataPortalServer
        /// </para><para>
        /// 内部值"Local"是Localproxy类的简称.服务处理也运行在客户端.        
        /// </para><para>
        /// 框架中所包含的处理类:
        /// <list>
        /// <item>
        /// <term>Wcdf,Wcdf.DataPortalClient.RemotingProxy</term>
        /// <description>与采用 .NET Remoting做为应用服务端通讯.</description>
        /// </item>
        /// <item>
        /// <term>Wcdf,Wcdf.DataPortalClient.EnterpriseServicesProxy</term>
        /// <description>与采用DCOM(COM+)做为应用服务端.</description>
        /// </item>
        /// <item>
        /// <term>Wcdf,Csla.DataPortalClient.WcfProxy</term>
        /// <description>与采用WCF框架做为应用服务端通讯.</description>
        /// </item>
        /// </list>
        /// 每种类似的代理对应各自的服务构架.        
        /// </para>
        /// </remarks>
        public static string DataPortalProxy
        {
            get
            {
                if (string.IsNullOrEmpty(_portalProxy))
                {
                    _portalProxy = ConfigurationManager.AppSettings["DataPortalProxy"];
                    if (string.IsNullOrEmpty(_portalProxy))
                        _portalProxy = "Local";
                }
                return _portalProxy;
            }
            set
            {
                _portalProxy = value;
                //DataPortal.ResetProxyType();
            }
        }

        private static string _portalUrl = null;

        /// <summary>
        /// 数据门户地址的URL字段串形式.        
        /// </summary>
        /// <value>URL格式字符串,需要以"\"结尾.</value>
        public static string DataPortalUrlString
        {
            get
            {
                if (_portalUrl == null)
                {
                    _portalUrl = ConfigurationManager.AppSettings["DataPortalUrl"];
                }
                return _portalUrl;
            }
            set
            {
                _portalUrl = value;
            }
        }

        /// <summary>
        /// 数据门户地址的URL格式.
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks>
        /// This value is read from the application configuration
        /// file with the key value "CslaDataPortalUrl". 
        /// </remarks>
        public static Uri DataPortalUrl
        {
            get { return new Uri(DataPortalUrlString); }
        }

        #endregion

        #region In-Memory Settings
        private static RunLocation? _logicRunLocation = WooCoo.RuntimeEnvironment.RunLocation;
        public static RunLocation? LogicRunLocation
        {
            get { return _logicRunLocation; }
            set { _logicRunLocation = value; }
        }
        #endregion

        #region Default context manager
        private class ApplicationContextManager : IContextManager
        {
            private const string _localContextName = "WooCoo.LocalContext";
            private const string _clientContextName = "WooCoo.ClientContext";
            private const string _globalContextName = "WooCoo.GlobalContext";

            public bool IsValid
            {
                get { return true; }
            }

            public string SessionID { get; set; }

            public IPrincipal GetUser()
            {
                IPrincipal current = Thread.CurrentPrincipal;
                return current;
            }

            public void SetUser(IPrincipal principal)
            {
                Thread.CurrentPrincipal = principal;
            }

            public HybridDictionary GetLocalContext()
            {
                LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_localContextName);
                return (HybridDictionary)Thread.GetData(slot);
            }

            public void SetLocalContext(HybridDictionary localContext)
            {
                LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_localContextName);
                Thread.SetData(slot, localContext);
            }

            public HybridDictionary GetClientContext()
            {
                if (RuntimeEnvironment.RunLocation == RunLocation.Server)
                {
                    LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_clientContextName);
                    return (HybridDictionary)Thread.GetData(slot);
                }
                else
                {
                    return (HybridDictionary)AppDomain.CurrentDomain.GetData(_clientContextName);

                }
            }

            public void SetClientContext(HybridDictionary clientContext)
            {
                if (RuntimeEnvironment.RunLocation == RunLocation.Server)
                {
                    LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_clientContextName);
                    Thread.SetData(slot, clientContext);

                }
                else
                {
                    AppDomain.CurrentDomain.SetData(_clientContextName, clientContext);
                }
            }

            public HybridDictionary GetGlobalContext()
            {
                LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_globalContextName);
                return (HybridDictionary)Thread.GetData(slot);
            }

            public void SetGlobalContext(HybridDictionary globalContext)
            {
                LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_globalContextName);
                Thread.SetData(slot, globalContext);
            }
        }

        #endregion        
    }
}
